<?php

namespace app\common;

use app\common\BusinessException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\ValidateException;
use think\Response;
use Throwable;

/**
 * 统一异常处理类
 * 用于根据不同异常类型进行针对性处理
 */
class ExceptionHandler extends Handle
{
    /**
     * 处理异常并返回统一格式响应
     *
     * @param Throwable $exception
     * @return Response
     */
    public function render($request, Throwable $exception): Response
    {

        // 判断环境
        if (env('app_debug')) {
            return parent::render($request, $exception);
        }

        // 根据异常类型进行不同处理
        if ($exception instanceof BusinessException) {
            // 业务异常处理
            return $this->handleBusinessException($exception);
        } elseif ($exception instanceof NoLoginException) {
            // 未登录异常处理
            return $this->handleNoLoginException($exception);
        } elseif ($exception instanceof ValidateException) {
            // 验证异常处理
            return $this->handleValidateException($exception);
        } elseif ($exception instanceof ModelNotFoundException || $exception instanceof DataNotFoundException) {
            // 数据不存在异常处理
            return $this->handleDataNotFoundException($exception);
        } elseif ($exception instanceof HttpException) {
            // HTTP异常处理
            return $this->handleHttpException($exception);
        } else {
            // 其他异常处理
            return $this->handleOtherException($exception);
        }
    }

    private function handleNoLoginException(NoLoginException $exception): Response
    {
        return json([
            'code' => $exception->getCode() ?: 400,
            'msg' => $exception->getMessage() ?: '未登录',
            'data' => null,
        ]);
    }

    /**
     * 处理业务异常
     *
     * @param BusinessException $exception
     * @return Response
     */
    private function handleBusinessException(BusinessException $exception): Response
    {
        return json([
            'code' => $exception->getCode() ?: 401,
            'msg' => $exception->getMessage() ?: '业务异常',
            'data' => null,
        ]);
    }

    /**
     * 处理验证异常
     *
     * @param ValidateException $exception
     * @return Response
     */
    private function handleValidateException(ValidateException $exception): Response
    {
        return json([
            'code' => 422,
            'msg' => '验证失败',
            'data' => $exception->getError(),
        ]);
    }

    /**
     * 处理数据不存在异常
     *
     * @param Throwable $exception
     * @return Response
     */
    private function handleDataNotFoundException(Throwable $exception): Response
    {
        return json([
            'code' => 404,
            'msg' => '请求的数据不存在',
            'data' => null,
        ]);
    }

    /**
     * 处理HTTP异常
     *
     * @param HttpException $exception
     * @return Response
     */
    private function handleHttpException(HttpException $exception): Response
    {
        return json([
            'code' => $exception->getStatusCode(),
            'msg' => $exception->getMessage() ?: 'HTTP请求异常',
            'data' => null,
        ]);
    }

    /**
     * 处理其他异常
     *
     * @param Throwable $exception
     * @return Response
     */
    private function handleOtherException(Throwable $exception): Response
    {
        // 记录异常日志
        $this->report($exception);

        // 非调试模式下返回通用错误信息
        if (!config('app.debug')) {
            return json([
                'code' => 500,
                'msg' => '服务器内部错误',
                'data' => null,
            ]);
        }

        // 调试模式下返回详细错误信息
        return json([
            'code' => 500,
            'msg' => $exception->getMessage(),
            'data' => [
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'trace' => $exception->getTraceAsString(),
            ],
        ]);
    }
}
